package bancosys.tec.utils.db.converter;

import java.io.File;
import java.io.FileNotFoundException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Class written using OracleToMysqlDbConverter as reference
 * 
 * @author Rafael Volpato
 * @created May 10, 2007
 */
public class OracleToHsqlDbConverter extends StatementDbConverter {
    private Set<String> numberFields = new TreeSet<String>();

    private Pattern numberFieldPattern = Pattern.compile("(\\w+)\\s+NUMBER\\s*\\(\\s*\\d+\\s*\\)\\s+NOT\\s+NULL");

    private String pkPatternDef = "ALTER\\s+TABLE\\s+(\\w+)\\s+ADD\\s+CONSTRAINT\\s+\\w+\\s+PRIMARY\\s+KEY\\s*\\(\\s*(\\w+)\\s*\\)";

    private Pattern pkPattern = Pattern.compile(this.pkPatternDef);

    private Pattern uniqPattern =
            Pattern.compile("ALTER\\s+TABLE\\s+\\w+\\s+ADD\\s+CONSTRAINT\\s+\\w+\\s+UNIQUE\\s*\\(\\s*(\\w+(,\\s*)?)+\\s*\\)");

    /**
     * Construtor.
     * 
     * @param inputFile arquivo de entrada.
     * @param outputFile arquivo de saida.
     * @param dbName nome do banco.
     * @throws FileNotFoundException caso nao encontre arquivo.
     * @throws MalformedURLException url malformada.
     */
    public OracleToHsqlDbConverter(File inputFile, File outputFile, String dbName) throws FileNotFoundException, MalformedURLException {
        super(inputFile, outputFile, dbName);
    }

    /**
     * Construtor.
     * 
     * @param inputFile arquivo de entrada.
     * @param outputFile arquivo de saida.
     * @param dbName nome do banco.
     */
    public OracleToHsqlDbConverter(URL inputFile, File outputFile, String dbName) {
        super(inputFile, outputFile, dbName);
    }

    /**
     * @param str statement.
     * @return statement convertido.
     */
    @Override
    protected String convertStatement(String str) {
        String s = str;

        // Ignore
        if (s.startsWith("COMMENT") || s.startsWith("CREATE UNIQUE") || s.startsWith("--") || s.startsWith("CREATE UNIQUE INDEX")) {
            return null;
        }

        Matcher uniqMatcher = this.uniqPattern.matcher(s);
        if (uniqMatcher.find()) {
            return null;
        }

        Matcher fieldMatcher = this.numberFieldPattern.matcher(s);
        while (fieldMatcher.find()) {
            this.numberFields.add(fieldMatcher.group(1));
        }

        Matcher pkMatcher = this.pkPattern.matcher(s);
        if (pkMatcher.find() && this.numberFields.contains(pkMatcher.group(2))) {
            s = s.replaceAll(this.pkPatternDef, s + this.getNewStatementDelimiterChar() + "\nALTER TABLE $1 ALTER COLUMN $2 IDENTITY\n");
        }

        s = s.replaceAll("DATE", "DATETIME");
        s = s.replaceAll("AUTH VARCHAR2\\(1 CHAR\\) DEFAULT '0'", "AUTH BOOLEAN DEFAULT 0");
        s = s.replaceAll("NCHAR", "CHAR");
        s = s.replaceAll("VARCHAR2\\(([0-9]+)( CHAR)?\\)", "VARCHAR($1)");
        s = s.replaceAll("CHAR\\(([0-9]+)( CHAR)?\\)", "CHAR($1)");
        s = s.replaceAll("CLOB", "LONGVARCHAR");
        s = s.replaceAll("BLOB", "LONGVARCHAR");
        s = s.replaceAll("NUMBER\\((\\d+,\\d+)\\)", "DECIMAL($1)");
        s = s.replaceAll("NUMBER\\(\\d+\\)", "INT");

        return s;
    }

    /**
     * @param line a linha.
     * @return <code>true</code> se encontrar delimitador, <code>false</code> se nao.
     */
    @Override
    protected boolean gotDelimiter(String line) {
        return line.matches("^" + this.getOldStatementDelimiterChar() + "$");
    }

    /**
     * @return delimitador velho.
     */
    @Override
    protected char getOldStatementDelimiterChar() {
        return '/';
    }

    /**
     * @return delimitador novo.
     */
    @Override
    protected char getNewStatementDelimiterChar() {
        return ';';
    }
}
